"""此文件提供光照效果和光线追踪。"""

import pygame

def cint(d) -> int:
    return d if type(d) is int else int(d)

class Sun(object):
    """提供光照效果"""
    def __init__(self, Display:pygame.surface.Surface) -> None:
        self.scr : pygame.surface.Surface = Display
        self.darkOrigin = pygame.Surface((1650, 40))
        self.darkOrigin.fill((0, 0, 0))
        self.lightOrigin = pygame.Surface((1650, 40))
        self.lightOrigin.fill((2, 2, 2))
    
    def draw(self, dark : int = -1):
        if dark < -1:
            return
        elif dark > 120:
            return False
        else:
            for row in range(0, 23):
                darkness : int = cint(dark / 2 + row * 2.5 + 1)
                self.darkOrigin.fill((darkness, darkness, darkness))
                self.scr.blit(self.darkOrigin, (0, 40*row), special_flags=pygame.BLEND_RGB_SUB)
            return True

def mid(x: int, a: int = 0, b: int = 15):
    if a <= x <= b:
        return x
    if x < a:
        x = a
    elif x > b:
        x = b
    return x

class light_block(object):
    """在光线追踪时传递动态光源信息"""
    def __init__(self, x:int, y:int, light:int = 15):
        """x, y:position. light: 真实光照强度(0~15)"""
        self.x = x
        self.y = y
        self.light = light

class Ray_Tracing(object):
    """光线追踪"""
    def __init__(self, Display : pygame.surface.Surface, Smooth_lighting : bool = False, gamma : int = 8) -> None:
        self.scr :pygame.surface.Surface = Display
        self.origin = pygame.Surface((40, 40))# if not Smooth_lighting else (20, 20))
        self.lightmap : list = []
        if Smooth_lighting == False:
            for row in range(23):
                li = []
                for col in range(42):
                    li.append(0)
                self.lightmap.append(li)
        else:
            raise ReferenceError()
        self.lightpics = [] # dark: max->min
        for i in range(15):
            pic = pygame.Surface((40, 40))
            pic.fill((i*gamma, i*gamma, i*gamma))
            self.lightpics.append(pic)
        #print('成功初始化')
        self.first_run = False
    
    def draw(self, dark : int = -1, lights : tuple = ()):
        if dark == -1:
            dark = 0
        dark = cint(dark * 15 / 120)
        dark = mid(dark, 0, 15)
        if self.first_run:
            print('enter func')
        for row in range(23):
            #y = self.lightmap[row]
            for col in range(42):
                self.lightmap[row][col] = mid(cint(dark + row/2), 0, 15)
        if self.first_run:
            print('normal light')
        if lights == ():
            pass
        else:
            for i in lights:
                x, y = mid(cint(i.x / 40), 0, 41), mid(cint(i.y / 40), 0, 22)
                self.lightmap[y][x] = min(15 - i.light, self.lightmap[y][x])
                if self.first_run:
                    print('ok 1')
                for j in range(i.light - 1):
                    x0 = cint(i.x/40) - j - 1
                    y0 = cint(i.y/40)
                    light_now = 15 - (i.light - j)
                    # 顺时针绕行, 逐个改变亮度值
                    if self.first_run:
                        print(f'check{j} x0={x0},y0={y0} light={light_now}')
                    while x0 < cint(i.x/40):
                        if 0<= x0 <=41 and 0<= y0 <=22:
                            self.lightmap[y0][x0] = min(light_now, self.lightmap[y0][x0])
                        x0 += 1
                        y0 -= 1
                    if self.first_run:
                        print(f'check{j} x0={x0},y0={y0} light={light_now}')
                    while y0 < cint(i.y/40):
                        if 0<= x0 <=41 and 0<= y0 <=22:
                            self.lightmap[y0][x0] = min(light_now, self.lightmap[y0][x0])
                        x0 += 1
                        y0 += 1
                    if self.first_run:
                        print(f'check{j} x0={x0},y0={y0} light={light_now}')
                    while x0 > cint(i.x/40):
                        if 0<= x0 <=41 and 0<= y0 <=22:
                            self.lightmap[y0][x0] = min(light_now, self.lightmap[y0][x0])
                        x0 -= 1
                        y0 += 1
                    if self.first_run:
                        print(f'check{j} x0={x0},y0={y0} light={light_now}')
                    while y0 > cint(i.y/40):
                        if 0<= x0 <=41 and 0<= y0 <=22:
                            self.lightmap[y0][x0] = min(light_now, self.lightmap[y0][x0])
                        x0 -= 1
                        y0 -= 1
                    if self.first_run:
                        print(f'check{j} x0={x0},y0={y0} light={light_now}')
        if self.first_run:
            print('high light')
        # render
        for row in range(23):
            for col in range(42):
                if self.first_run and col == 0:
                    print(f'rendering in row{row}')
                    if row == 2:
                        print(f'rendering row 2 -- col {col}, lightmap = {self.lightmap[row][col]}')
                self.scr.blit(self.lightpics[mid(self.lightmap[row][col], 0, 14)], (col*40, row*40), special_flags=pygame.BLEND_RGB_SUB)
        if self.first_run:
            print('render finish')
            self.first_run = False
    
    def get_client(self, x:int, y:int):
        x0, y0 = mid(cint(x/40), 0, 41), mid(cint(y/40), 0, 22)
        return 15 - self.lightmap[y0][x0]